package scau.cn.component.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

import javax.xml.transform.Source;

import scau.cn.OpenedFileTable;
import scau.cn.component.domain.Catalog;
import scau.cn.component.domain.FileN;
import scau.cn.fat.FAT;

/**
 * @author xiao
 * @date 2019/11/23 下午 3:37
 */
public class FileOp {
	// -------------------------------------------构造器-------------------------
	public FileOp() {
	}

	// ----------------------------------方法---------------------------------
	/**
	 * 建立文件
	 *
	 * @param input     建立文件输入的名字
	 * @param attribute * 
	 * 第 0 位表示文件为只读文件，
	 * 第 1 位表示文件为系统文件，
	 * 第 2 位表示文件为可读、可写的普通文件 
	 * 第 3位若为1表示该登记项不是文件的登记项，而是目录的登记项，其余几位闲置未用
	 * @param catalog   代表目录对象
	 * @throws Exception 异常信息
	 */
	public static FileN createFile(String input, byte attribute, Catalog catalog) throws Exception {
		// name={1,0,0} 则name为{1,0,0,0}
		byte[] name = input.getBytes();
		
		if (name.length > 3) {
			throw new Exception("文件长度过长");
		}
		int nameAndLength = 0;
		for (int i = 0; i < 3; i++) {
			if (name.length - 1 >= i) {
				nameAndLength = nameAndLength + name[i];
			}
			else {
				nameAndLength+=32;
			}
			nameAndLength = nameAndLength << 8;
		}
		//注意Length加1是在这里加的而不是在new FileN()中加的
		nameAndLength += 1;
		System.out.println(nameAndLength);
		if (!catalog.findFileName(nameAndLength)) {
			// TODO:不知道怎么传 type 先传个short 1
			FileN file = new FileN(nameAndLength, (short) 1, attribute, catalog.getFat(), catalog);
			catalog.addComponent(file);
			File file1 = new File(file.findPath());
			System.out.println(file1.getAbsolutePath());
			if(!file1.exists()) {
				file1.createNewFile();
			}
			return file;
		} else {
			
			throw new Exception("该文件名已经存在");
			
		}
	}

	/**
	 * 打开文件： 在当前目录下打开文件
	 * 
	 * @param fileName        : 文件的名称
	 * @param operationOfType ： 文件的操作类型，只读为0，可读可写为1
	 * @param catalog         : 当前目录
	 * @author 严浩强
	 */
	public boolean openFile(String fileName, int operationOfType, Catalog catalog) {
		FileN file;
		// 判断当前目录下是否存在该文件（不判断子目录）
		if ((file = catalog.getFileFromComponent(fileName)) != null) {
			int opType = file.getOpType();
			// 判断要求的操作类型是否符合要求
			if (operationOfType == 1 && opType == 0) {
				// 如果文件属性只能读，但却要求写就报错
				return false;
			}
			OpenedFileTable openedFileTable = OpenedFileTable.getOpenedFileTable();
			openedFileTable.add(file);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 读取文件：（这个一读就读取所有了，所以之后显示文件内容那个功能就不写了） 读取的是当前目录下的文件（不需要查子目录） 这个功能忽略了读指针
	 * 
	 * @param fileName：文件名字
	 * @param catalog： 当前目录
	 * @return content: 文件全部内容
	 * @author 严浩强
	 */
	public String readFile(String fileName, Catalog catalog) {
		OpenedFileTable openedFileTable = OpenedFileTable.getOpenedFileTable();
		// 因为这个openFile会自动检查该目录中是否存在文件
		// 而且还会自动根据是否已经存在再已打开文件表中来智能判断时候加入到已打开文件表
		// 所以直接调用这个方法
		if (openFile(fileName, 0, catalog)) {
			// 老师要求里面是分读和写的，但我们这里部分，直接为读，而且一读读出全部
			FileN fileN = catalog.getFileFromComponent(fileName);
			try {
				// 注意这一行代码还未完善，等测试时再完善
				File file = new File(fileN.findPath());
				if(file.exists()) {
					FileReader fr = new FileReader(file);
					BufferedReader br = new BufferedReader(fr);
					StringBuilder content = new StringBuilder();
					String s;
					while ((s = br.readLine()) != null) {
						content.append(s);
					}
					br.close();
					fr.close();
					return content.toString();
				} else {
					return null;
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 写文件（覆盖写）：
	 * 
	 * @param fileName：文件名字
	 * @param catalog： 当前目录
	 * @param content: 所写的内容
	 * @return
	 * @author 周晓峰，严浩强
	 * @throws Exception 
	 */
	public boolean writeFile(String fileName, Catalog catalog, String content) throws Exception {
		OpenedFileTable openedFileTable = OpenedFileTable.getOpenedFileTable();
		// 因为这个openFile会自动检查该目录中是否存在文件
		// 而且还会自动根据是否已经存在再已打开文件表中来智能判断时候加入到已打开文件表
		// 所以直接调用这个方法
		if (openFile(fileName, 1, catalog)) {
			FileN fileN = catalog.getFileFromComponent(fileName);
			if (fileN.getOpType() == 1) {
				FAT fat = fileN.getFat();
				int lengthOfContent = content.length() - 64;
				// 我们覆盖写的时候释放这个文件的所有磁盘块，再找新的磁盘块。
				fileN.clearAllDiskMemory();
				int length = 1;
				while (lengthOfContent > 0) {
					int last = fat.findFree();
					if (last == -1) {
						return false;
					}
					fat.setStatus(fileN.findLastDiskMemory(), last);
					fat.setStatus(last, 255);
					lengthOfContent -= 64;
					length++;
				}
				fileN.setLength((byte)length);
				try {
					// 这一行代码路径还未完善
					File file = new File(fileN.findPath());
					if(file.exists()) {
						FileWriter fw = new FileWriter(file);
						BufferedWriter bw = new BufferedWriter(fw);
						bw.write(content);
						bw.close();
						fw.close();
						return true;
					}
					return false;
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			} else {
				throw new Exception("文件只能读不能写1");
			}
		} else {
			throw new Exception("文件只能读不能写");
		}
		return false;
	}

	/**
	 * 关闭文件
	 * 
	 * @throws Exception
	 */
	public boolean closeFile(String fileName, Catalog catalog) throws Exception {
		FileN file;
		// 判断当前目录下是否存在该文件（不判断子目录）
		if ((file = catalog.getFileFromComponent(fileName)) != null) {
			OpenedFileTable openedFileTable = OpenedFileTable.getOpenedFileTable();
			openedFileTable.remove(file);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 删除文件
	 */
	public boolean deleteFile(String fileName, Catalog catalog) throws Exception {
		FileN fileN = catalog.getFileFromComponent(fileName);
		//判断文件是否在当前目录下
		if (fileN != null) {
			// 判断文件是否在打开文件表中，保证打开了该文件就不能删除
			if (OpenedFileTable.getOpenedFileTable().judgeExist(fileN) == false) {
				catalog.deleteComponent(fileN);
				//判断文件是否删除成功，保证文件删除占用的FAT
				if (fileN.delete()==true) {
					File file = new File(fileN.findPath());
					if(file.exists()) {
						file.delete();
						return true;
					}
					return false;
				}
				else {
					return false;
				}
			} else {
				throw new Exception("文件运行中，无法删除");
			}
		} else {
			throw new Exception("该文件不存在");
		}
	}

	/**
	 * 改变文件属性
	 * @param fileName        : 文件的名称
	 * @param newType         ： 文件新的操作类型，只读为0，可读可写为1
	 * @param catalog         : 当前目录
	 */
	public boolean change(String fileName, int newType, Catalog catalog) {
		FileN file;
		// 判断当前目录下是否存在该文件（不判断子目录）
		if ((file = catalog.getFileFromComponent(fileName)) != null) {
			int opType = file.getOpType();
			file.setOpType(newType);
			return true;
		} else {
			return false;
		}
	}
	
}
